/*
 * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */
package demo.parallelcore;

import java.util.Collection;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.Map;
import java.util.Optional;
import java.util.function.Function;
import java.util.stream.Collector;
import java.util.stream.Collectors;


/**
 * This program is demo how to use the conversion operator like toArray,
 * collect(Collectors.toList()), collect(Collectors.toCollection())
 * @author tyan
 */

public class Conversion extends DemoHelper {
    /*
     * Convert products which is most expensive in the same category into an
     * array
     * @param   func Function convert Product to T, T could be any type that
     *          Product can convert, like price
     * @return  product array which is in every category, value of T is highest
    */
    public static <T extends Comparable<T>> Product[] mostTProductsByCategory(
            Function<Product, T> func){
        //A product comparator which compare with given function
        Comparator<Product> unitPriceComparator = Comparator.comparing(func);
        //Collector that group product with category, also find out product
        //which value of T is biggest.
        Collector<Product, ?, Map<String, Optional<Product>>> categoryToMostT
            = Collectors.groupingBy(Product::getCategory,
                Collectors.maxBy(unitPriceComparator));
        return (Product[]) products.parallelStream().
        //Collect product to a Map, which key is category, value is
        //product in same category that is most with using comparator<T>
        collect(categoryToMostT).
        //get all products
        values().stream().
        //get real product
        map(Optional::get).
        //Convert it into a array
        toArray(Product[]::new);
    }

    /*
     * Convert customers to a distinct countries list
     * @param   ordered true  keep original countries list order
     *                  false not keep original countries list order
     * @return a distinct ordered/unordered countires list for all of customers
     *         by given ordered flag
    */
    public static Collection<String> countries(boolean ordered) {
        if(ordered)
            /*
             *Use distinct() follow with collect(Collectors.toCollection) to get
             *unique countires linked list.
             *Note this way can generate target container
            */
            return customers.parallelStream().
                    //map customer to its country
                    map(Customer::getCountry).
                    //distinct all countries
                    distinct().
                    //convert it to a list
                    collect(Collectors.toCollection(LinkedList::new));
        else
            /*
             *Use collect(Collectors.toSet) to get unique countires list.
             *Note the difference between this and first one is this way doesn't
             *gurantee the order
            */
            return customers.parallelStream().
                    //map customer to its country
                    map(Customer::getCountry).
                    //convert it to a set
                    collect(Collectors.<String>toSet());
    }
}
